Skip to content

Pin light theme on /workspaces/ at wrapper scope#772

Merged
backnotprop merged 1 commit into
mainfrom
fix/workspaces-light-mode
May 22, 2026
Merged

Pin light theme on /workspaces/ at wrapper scope#772
backnotprop merged 1 commit into
mainfrom
fix/workspaces-light-mode

Conversation

@backnotprop
Copy link
Copy Markdown
Owner

Summary

Follow-up to #771. The earlier "force light mode on /workspaces/" change added the .light class to <html> via a head-slot inline script. That works for the first paint, but then gets undone:

The ModeToggleIsland React component in Nav.astro hydrates on mount and runs applyTheme(theme), which always calls classList.remove('light') first before re-applying based on the saved theme cookie. So if a visitor's saved theme is dark, the page flashes light then flips to dark a few hundred ms later — which is what was happening in production after #771 merged.

Fix

Pin the light-theme CSS variables inside a .ws-force-light wrapper scope on the workspaces page. The toggle component can still flip the global .light class on/off, but the workspaces page's tokens are locked in at the wrapper level and aren't affected.

Net effect: /workspaces/ is deterministically light regardless of the visitor's saved theme preference, and the rest of the site continues to honor the toggle as before.

Test plan

  • Hard-refresh https://plannotator.ai/workspaces/ with plannotator-theme=dark cookie set → page renders light, doesn't flash
  • Set plannotator-theme=light → still light (unchanged)
  • Navigate to /docs/ after merging → renders dark (or whatever the saved theme is), confirming the override is page-scoped
  • Click the dark/light toggle in the nav while on /workspaces/ → toggle still works on the rest of the site if you navigate away; /workspaces/ itself stays light

Generated with Devin

The earlier force-light approach (adding the `.light` class to <html>
from a head script) gets undone the moment the React ModeToggleIsland
hydrates: its mount effect always calls `classList.remove('light')`
before re-applying based on the saved cookie. If the visitor's saved
theme is dark, the page flashes light then flips to dark.

Inline the light theme tokens inside `.ws-force-light` instead. The
toggle component can still flip the global `.light` class on/off, but
the workspaces page's tokens are pinned at the wrapper scope and
unaffected. Result: deterministic light mode regardless of the
visitor's saved preference.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@backnotprop backnotprop merged commit d9832b7 into main May 22, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant